package biz

import (
	amount_v1 "amount1/api/Amount1Server/v1"
	"amount1/internal/utils"
	"context"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-resty/resty/v2"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/trace"
)

type Amount1BizInterface interface {
	// 编辑库存
	EditOrderMain(ctx context.Context, id uint32, changeValue int64) error
	EditOrderMainWithTX(ctx context.Context, id uint32, changeValue int64) error
	// 编辑流水
	AddOrderStatement(ctx context.Context, orderMainId uint32, changeValue int64, orderNo string) error
	AddOrderStatementWithTX(ctx context.Context, orderMainId uint32, changeValue int64, orderNo string) error
	// 删除流水
	DelOrderStatement(ctx context.Context, id uint32, orderNo string) error
	DelOrderStatementWithTX(ctx context.Context, id uint32, orderNo string) error

	// 测试删除redis的不存在的key会不会报错 - 不会
	DelRedisKeyDemo(ctx context.Context) error
	// redis操作
	CurrentRedisOption(ctx context.Context) error
}

type Amount1BizStruct struct {
	amount1Repo Amount1BizInterface
	logger      log.Logger
	// Notice 事务
	TM Transaction
	// httpClient
	httpRestyClient *resty.Client
}

func NewAmount1Biz(biz Amount1BizInterface, logger log.Logger, tm Transaction, restyClient *resty.Client) *Amount1BizStruct {
	return &Amount1BizStruct{
		amount1Repo:     biz,
		logger:          logger,
		TM:              tm,
		httpRestyClient: restyClient,
	}
}

func (a *Amount1BizStruct) TransOutOrder(ctx context.Context, req *amount_v1.TransOutOrderRequest) (*amount_v1.Empty, error) {
	ctx, span := otel.Tracer("BIZ").Start(ctx, "TransOutOrderBiz", trace.WithSpanKind(trace.SpanKindInternal))
	defer span.End()

	reply := &amount_v1.Empty{}

	// 在本地事务中执行：修改 order_main表、在order_statement表中新增记录
	errTransaction := a.TM.InTx(ctx, func(ctx context.Context) error {
		// 这里需要从ctx中获取tx
		err1 := a.amount1Repo.EditOrderMainWithTX(ctx, req.Id, req.StockChange)
		if err1 != nil {
			return err1
		}

		err2 := a.amount1Repo.AddOrderStatementWithTX(ctx, req.Id, req.StockChange, req.OrderNo)
		if err2 != nil {
			return err2
		}

		return nil
	})

	if errTransaction != nil {
		return nil, errTransaction
	}

	// Notice 加一个Redis操作，测试trace
	errRedis := a.amount1Repo.CurrentRedisOption(ctx)
	if errRedis != nil {
		return nil, errRedis
	}

	return reply, nil
}

func (a *Amount1BizStruct) TransOutOrderCompensate(ctx context.Context, req *amount_v1.TransOutOrderCompensateRequest) (*amount_v1.Empty, error) {
	ctx, span := otel.Tracer("BIZ").Start(ctx, "TransOutOrderCompensateBiz", trace.WithSpanKind(trace.SpanKindInternal))
	defer span.End()

	reply := &amount_v1.Empty{}

	// 在本地事务中执行：修改order_main表、删除order_statement表中对应的流水记录
	errTransaction := a.TM.InTx(ctx, func(ctx context.Context) error {
		err1 := a.amount1Repo.EditOrderMainWithTX(ctx, req.Id, req.StockChange)
		if err1 != nil {
			return err1
		}

		err2 := a.amount1Repo.DelOrderStatementWithTX(ctx, req.Id, req.OrderNo)
		if err2 != nil {
			return err2
		}

		return nil
	})

	if errTransaction != nil {
		return nil, errTransaction
	}

	return reply, nil
}

func (a *Amount1BizStruct) DelRedisKeyDemo(ctx context.Context, req *amount_v1.Empty) (*amount_v1.Empty, error) {

	reply := &amount_v1.Empty{}

	errDel := a.amount1Repo.DelRedisKeyDemo(ctx)
	if errDel != nil {
		return nil, errDel
	}

	return reply, nil

}

func (a *Amount1BizStruct) TestHttpRequest(ctx context.Context, req *amount_v1.HttpReq) (*amount_v1.Empty, error) {
	ctx, span := otel.Tracer("BIZ").Start(ctx, "TestHttpRequestBiz", trace.WithSpanKind(trace.SpanKindInternal))
	defer span.End()

	name := req.Name
	reply := &amount_v1.Empty{}

	// GET 请求
	errGET := a.httpGet(ctx, name)
	if errGET != nil {
		return nil, errGET
	}

	// POST 请求
	errPOST := a.httpPost(ctx, name)
	if errPOST != nil {
		return nil, errPOST
	}

	return reply, nil
}

func (a *Amount1BizStruct) TestAsyncRequestCtxWithoutCancel(ctx context.Context, req *amount_v1.HttpReq) (*amount_v1.Empty, error) {
	ctx, span := otel.Tracer("BIZ").Start(ctx, "TestAsyncRequestCtxWithoutCancelBiz", trace.WithSpanKind(trace.SpanKindInternal))
	defer span.End()

	name := req.Name
	reply := &amount_v1.Empty{}

	// Notice 发送请求的方法 sleep了2秒测试!!!

	// Notice 使用项目的ctx发送请求，因为在发请求里面sleep了2秒，所以这样做的话会报错： context canceled
	//go func() {
	//	errGET := a.httpGetCtxWithoutCancel(ctx, name)
	//	if errGET != nil {
	//		fmt.Println("errGet: ", errGET)
	//	}
	//
	//	// POST 请求
	//	errPOST := a.httpPostCtxWithoutCancel(ctx, name)
	//	if errPOST != nil {
	//		fmt.Println("errPOST: ", errPOST)
	//	}
	//}()

	// Notice 使用 WithoutCancel发送请求
	ctxWithoutCancel := utils.WithoutCancel(ctx)
	go func() {
		errGET := a.httpGetCtxWithoutCancel(ctxWithoutCancel, name)
		if errGET != nil {
			fmt.Println("errGet: ", errGET)
		}

		// POST 请求
		errPOST := a.httpPostCtxWithoutCancel(ctxWithoutCancel, name)
		if errPOST != nil {
			fmt.Println("errPOST: ", errPOST)
		}
	}()

	return reply, nil
}
